import Glibc

class Timer {
    private let CLOCK_REALTIME = 0
    private var start_timespec = timespec()
    private var end_timespec = timespec()
    private var time_spec = timespec()
    func start() {
        clock_gettime(Int32(CLOCK_REALTIME),&start_timespec)
    }
    
    func stop() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&end_timespec)
        let start_time = Double(start_timespec.tv_sec * 1_000_000 + start_timespec.tv_nsec / 1_000)
        let end_time = Double(end_timespec.tv_sec * 1_000_000 + end_timespec.tv_nsec / 1_000)
        let time = end_time - start_time
        return time / 1_000
    }
    func getTime() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&time_spec)
        return Double(time_spec.tv_sec * 1_000_000 + time_spec.tv_nsec / 1_000)
    }
}

let timer = Timer()

let input = 3000000

func GenerateFakeRandomInteger() -> [Int] {
    let resource: [Int] = [12, 43, 56, 76, 89, 54, 45, 32, 35, 47, 46, 44, 21, 37, 84]
    return resource;
}

func GenerateFakeRandomFloat() -> [Double] {
    let resource: [Double] = [12.2, 43.5, 56.2, 76.6, 89.7, 54.9, 45.2, 32.5, 35.6, 47.2, 46.6, 44.3, 21.2, 37.6, 84.57]
    return resource;
}

func GenerateFakeRandomBool() -> [Bool] {
    let resource: [Bool] = [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true]
    return resource
}

func GenerateFakeRandomString() -> [String] {
    let resource: [String] = ["Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op"]
    return resource
}

func GenerateFakeRandomIndex()-> [Int] {
	let resource: [Int] = [3, 14, 44, 25, 91, 38, 82, 88, 64, 81, 70, 90, 33, 63, 70];
    return resource;
}

func integerArray() -> Double {
    let count = input
    let resources = GenerateFakeRandomInteger()
    let integerIndexes = GenerateFakeRandomIndex();
    var res: [Int] = [0, 0, 0, 0, 0];
    var num = 1
    // var res = 1
    timer.start()
    let length = resources.count - 1
    let resLength = res.count - 1
    for i in 0..<count {
        // res += resources[i % res & length]
        num += integerIndexes[i % num & length];
        res[i & resLength] = resources[i % num & length];
    }
    let time = timer.stop()
    var tmp = 1;
    for i in 0..<5 {
       tmp += res[i] 
    }
    print(tmp)
    return time
}

func floatArray() -> Double {
    let count = 3000000
	var res: [Double] = [0.0, 0.0, 0.0, 0.0, 0.0];
    let resources = GenerateFakeRandomFloat()
    let integerIndexes = GenerateFakeRandomIndex();
    var num = 1
    /* var res = 1.0 */
    timer.start()
    let length = resources.count - 1
    let resLength = res.count - 1
    for i in 0..<count {
        num += integerIndexes[i % num & length];
        /* res += resources[i % integerIndexes[i % 15] % 15]; */
		res[i & resLength] = resources[i % num & length];
    }
    let time = timer.stop()
    var tmp = 0.0;
    for i in 0..<5 {
       tmp += res[i] 
    }
    print(tmp)
    return time
}

func boolArray() -> Double {
    let count = input
    let resources = GenerateFakeRandomBool()
    let integerIndexes = GenerateFakeRandomIndex();
    var res: [Int] = [0, 0, 0, 0, 0];
    var num = 1
    timer.start()
    let length = resources.count - 1
    let resLength = res.count - 1
    for i in 0..<count {
        num += integerIndexes[i % num & length];
        if (resources[i % num & length]) {
            res[i & resLength] = integerIndexes[i & length]
        }
    }
    let time = timer.stop()
    var tmp = 0;
    for i in 0..<5 {
       tmp += res[i] 
    }
    print(tmp)
    return time
}

func stringArray() -> Double {
    let count = 3000000 / 100;
    let resources = GenerateFakeRandomString()
    var res: [Int] = [Int](repeating: 0, count: 3)
    timer.start()
    for i in 0..<count {
        res[i % res.count] += resources[i % 15].count;
    }
    let time = timer.stop()
    var sum = 0
    for i in 0..<res.count {
        sum += res[i]
    }
    print(sum)
    return time
}

class Obj {
    var value: Int = 0
    init(value: Int) {
        self.value = value
    }
}

func GenerateFakeRandomObject() -> [Obj] {
    let resource: [Obj] = [Obj](repeating: Obj(value: Int.random(in: 1..<10)), count: 15)
    return resource
}

func objectArray() -> Double {
    let count = input
    /* var res = 1; */
    var res: [Obj] = [Obj](repeating: Obj(value: Int.random(in: 1..<10)), count: 5)
    let resources = GenerateFakeRandomObject()
    timer.start()
    for i in 0..<count {
        /* res += resources[i % res % 15].value */
        res[i % 5] = resources[i % 15];
    }
    let time = timer.stop()
    /* print(res) */
    var tmp = 1;
    for i in 0..<5 {
        tmp += res[i].value
    }
    print(tmp)
    return time
}

// 测试结果
print("Array Access - IntegerArray: \t\(integerArray())\tms")
print("Array Access - FloatArray: \t\(floatArray())\tms")
print("Array Access - BoolArray: \t\(boolArray())\tms")
print("Array Access - StringArray: \t\(stringArray())\tms")
print("Array Access - ObjectArray: \t\(objectArray())\tms")
